/*************************************************************************
	> File Name: decvice.c
	> Author: Thinking
	> Mail: program_code@sohu.com 
	> Created Time: Wed 16 Jun 2021 05:45:46 AM PDT
 ************************************************************************/

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/inode.h>

#define BUFFER_MAX    (64)
#define OK            (0)
#define ERROR         (-1)


static int major	= 250;
static struct cdev struct_dev_read;
static struct cdev struct_dev_write; 
static struct class* cls;

char buffer[BUFFER_MAX] = {0x00};
int open_count = 0;
struct semaphore sema;

int dev_open(struct inode *p, struct file *f)
{
	down(&sema);
    printk(KERN_INFO "dev_open\r\n");
	if(open_count) {
		return -EBUSY;
	}
	open_count++;
	up(&sema);
    return 0;

}


ssize_t dev_write(struct file *f, const char __user *u, size_t s, loff_t *l)
{
	int w = 0;
    printk(KERN_INFO "dev_write\r\n");
	w = BUFFER_MAX>s?s:BUFFER_MAX;
	if(copy_from_user(buffer,u,w)){
		return -EFAULT;
	}
    return w;

}

ssize_t dev_read(struct file *f, char __user *u, size_t s, loff_t *l)
{

    int r = 0;
	printk(KERN_INFO "dev_read\r\n");
	r = BUFFER_MAX>s?s:BUFFER_MAX;
	if(copy_to_user(u,buffer,r)){
		return -EFAULT;
	}
	return r;

}

static struct file_operations device_rop= {
	.owner = THIS_MODULE,
	.open = dev_open,
	.read = dev_read,
	.write = dev_write,
};

static struct file_operations device_wop= {
	.owner = THIS_MODULE,
	.open = dev_open,
	.read = dev_read,
	.write = dev_write,
};


int dev_init(void)
{
	dev_t devid;
	printk(KERN_INFO "dev driver init \n");
	alloc_chrdev_region(&devid,4,238,"dread");
	major = MAJOR(devid);


	printk(KERN_INFO "MAJOR Number is %d\n",MAJOR(devid));
    printk(KERN_INFO "MINOR Number is %d\n",MINOR(devid));

	cdev_init(&struct_dev_read,&device_rop);
	cdev_init(&struct_dev_write,&device_wop);

	cdev_add(&struct_dev_read,devid,1);


	cls = class_create(THIS_MODULE,"device_fft");
	device_create(cls,0,MKDEV(major,0),0,"device_fft");
	sema_init( &sema, 5 );

    return 0;
}

void __exit dev_exit(void)
{
	printk(KERN_INFO "dev driver exit \n");
	device_destroy(cls,MKDEV(major,0));

	class_destroy(cls);

	cdev_del(&struct_dev_read);
	cdev_del(&struct_dev_write);

	unregister_chrdev_region(MKDEV(major,0),4);

	
	return;
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
